package com.vidyu.datalayer.dataaccesscomponents.impl;

import com.vidyu.datalayer.dataaccesscomponents.BaseDao;
import org.hibernate.impl.SessionFactoryImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.orm.hibernate3.HibernateTemplate;

import java.util.List;

/**
 * Base operations of DAO objects
 */
public class BaseDaoImpl implements BaseDao {

    @Autowired
    private HibernateTemplate hibernateTemplate;
    private static final String MYSQL_QUERY_SUFFIX = "MySQL";

    /**
     * Execute a named query.
     * <p>A named query is defined in a Hibernate mapping file.
     *
     * @param queryName the name of a Hibernate query in a mapping file
     * @return a {@link java.util.List} containing the results of the query execution
     * @throws org.springframework.dao.DataAccessException
     *          in case of Hibernate errors
     * @see org.hibernate.Session#getNamedQuery(String)
     */
    public List findByNamedQuery(String queryName) throws DataAccessException {
        queryName = getRightQuery(queryName);
        return hibernateTemplate.findByNamedQuery(queryName);
    }

    /**
     * Execute a named query, binding one value to a "?" parameter in
     * the query string.
     * <p>A named query is defined in a Hibernate mapping file.
     *
     * @param queryName the name of a Hibernate query in a mapping file
     * @param value     the value of the parameter
     * @return a {@link java.util.List} containing the results of the query execution
     * @throws org.springframework.dao.DataAccessException
     *          in case of Hibernate errors
     * @see org.hibernate.Session#getNamedQuery(String)
     */
    public List findByNamedQuery(String queryName, Object value) throws DataAccessException {
        queryName = getRightQuery(queryName);
        return hibernateTemplate.findByNamedQuery(queryName, value);
    }

    /**
     * Execute a named query binding a number of values to "?" parameters
     * in the query string.
     * <p>A named query is defined in a Hibernate mapping file.
     *
     * @param queryName the name of a Hibernate query in a mapping file
     * @param values    the values of the parameters
     * @return a {@link java.util.List} containing the results of the query execution
     * @throws org.springframework.dao.DataAccessException
     *          in case of Hibernate errors
     * @see org.hibernate.Session#getNamedQuery(String)
     */
    public List findByNamedQuery(String queryName, Object... values) throws DataAccessException {
        queryName = getRightQuery(queryName);
        return hibernateTemplate.findByNamedQuery(queryName, values);
    }

    /**
     * Execute a named query, binding one value to a ":" named parameter
     * in the query string.
     * <p>A named query is defined in a Hibernate mapping file.
     *
     * @param queryName the name of a Hibernate query in a mapping file
     * @param paramName the name of parameter
     * @param value     the value of the parameter
     * @return a {@link java.util.List} containing the results of the query execution
     * @throws org.springframework.dao.DataAccessException
     *          in case of Hibernate errors
     * @see org.hibernate.Session#getNamedQuery(String)
     */
//    public List findByNamedQueryAndNamedParam(String queryName, String paramName, Object value) throws DataAccessException {
//        queryName = getRightQuery(queryName);
//        return hibernateTemplate.findByNamedQueryAndNamedParam(queryName, paramName, value);
//    }

    /**
     * Execute a named query, binding a number of values to ":" named
     * parameters in the query string.
     * <p>A named query is defined in a Hibernate mapping file.
     *
     * @param queryName  the name of a Hibernate query in a mapping file
     * @param paramNames the names of the parameters
     * @param values     the values of the parameters
     * @return a {@link java.util.List} containing the results of the query execution
     * @throws org.springframework.dao.DataAccessException
     *          in case of Hibernate errors
     * @see org.hibernate.Session#getNamedQuery(String)
     */
//    public List findByNamedQueryAndNamedParam(String queryName, String[] paramNames, Object[] values) throws DataAccessException {
//        queryName = getRightQuery(queryName);
//        return hibernateTemplate.findByNamedQueryAndNamedParam(queryName, paramNames, values);
//    }

    /**
     * Execute a named query, binding the properties of the given bean to
     * ":" named parameters in the query string.
     * <p>A named query is defined in a Hibernate mapping file.
     *
     * @param queryName the name of a Hibernate query in a mapping file
     * @param valueBean the values of the parameters
     * @return a {@link java.util.List} containing the results of the query execution
     * @throws org.springframework.dao.DataAccessException
     *          in case of Hibernate errors
     * @see org.hibernate.Query#setProperties
     * @see org.hibernate.Session#getNamedQuery(String)
     */
//    public List findByNamedQueryAndValueBean(String queryName, Object valueBean) throws DataAccessException {
//        queryName = getRightQuery(queryName);
//        return hibernateTemplate.findByNamedQueryAndValueBean(queryName, valueBean);
//    }

    private String getRightQuery(String queryName) {
        SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl) hibernateTemplate.getSessionFactory();
        if (sessionFactoryImpl.getNamedSQLQuery(queryName + MYSQL_QUERY_SUFFIX) != null) {
            return queryName + MYSQL_QUERY_SUFFIX;
        }
        return queryName;
    }

    /**
     * Execute a named query, binding a number of values to "?" parameters 
     * in the query string.
     * <p>A named query is defined in a Hibernate mapping file.
     * 
     * @param queryName  the name of a Hibernate query in a mapping file
     * @param values     the values of the parameters
     * @return n {@link int} number of updated rows
     */
//    public int updateByNamedQuery(String queryName, Object[] values) {
//        SessionFactoryImpl sessionFactoryImpl = (SessionFactoryImpl) hibernateTemplate.getSessionFactory();
//        String mysqlQuery = sessionFactoryImpl.getNamedQuery(queryName).getQuery();
//        return hibernateTemplate.bulkUpdate(mysqlQuery, values);
//    }

    /**
     * Execute a named query, binding a number of values to ":" named
     * parameters in the query string.
     * <p>A named query is defined in a Hibernate mapping file.
     * 
     * @param queryName  the name of a Hibernate query in a mapping file
     * @param paramNames the names of the parameters
     * @param values     the values of the parameters
     * @return n {@link int} number of updated rows
     * @throws org.springframework.dao.DataAccessException
     *          in case of Hibernate errors
     * @see org.hibernate.Query#setProperties
     * @see org.hibernate.Session#getNamedQuery(String)
     * @throws IllegalArgumentException in case of wrong input parametes
     */
//    public int updateByNamedQuery(String queryName, String[] paramNames, Object[] values) throws DataAccessException, IllegalArgumentException {
//        if (paramNames.length == values.length) {
//            queryName = getRightQuery(queryName);
//
//            Query query = hibernateTemplate.getSessionFactory().getCurrentSession().getNamedQuery(queryName);
//
//            for (int i = 0; i < paramNames.length; i++) {
//                if (values[i] instanceof Collection) {
//                    query.setParameterList(paramNames[i], (Collection) values[i]);
//                } else if(values[i] instanceof Object[]) {
//                    query.setParameterList(paramNames[i], (Object[]) values[i]);
//                } else {
//                    query.setParameter(paramNames[i], values[i]);
//                }
//            }
//            return query.executeUpdate();
//        } else {
//            throw new IllegalArgumentException("paramName and values parameters should have identical length.");
//        }
//    }
}
